package com.mango.httpforward.web.controller;


import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.mango.httpforward.web.config.ForwardProperties;
import com.mango.httpforward.web.holder.ForwardHolder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/forward")
@RequiredArgsConstructor
public class HttpForwardController {

    private final ForwardProperties forwardProperties;

    @RequestMapping(path = "/{target}/{key}/**")
    @ResponseBody
    public void index(@PathVariable String target, @PathVariable String key,
                      HttpServletRequest request, HttpServletResponse response)
        throws IOException {
        InputStream ins = request.getInputStream();
        String text = IoUtil.read(ins, Charset.defaultCharset());
        String queryString = request.getQueryString();
        log.info("target = {}, params = {}, queryString = {}", target, text, queryString);

        Enumeration<String> headerNames = request.getHeaderNames();
        String method = request.getMethod();
        String contentType = request.getContentType();
        String servletPath = request.getServletPath();
        log.info("method = {}, contentType = {}, servletPath = {}, headers = {}", method, contentType, servletPath, JSONUtil.parse(headerNames));


        String requestUrl = getRequestUrl(servletPath, target, key);
        log.info("requestUrl = {}", requestUrl);
        if (StrUtil.isBlank(requestUrl)) {
            response.setCharacterEncoding("UTF-8");
            JSONObject result = JSONUtil.createObj().set("error", "0001").set("message", "请求地址不能为空");
            result.write(response.getWriter());
            return;
        }

        UrlBuilder urlBuilder = UrlBuilder.of(requestUrl);
        if (StrUtil.isNotBlank(queryString)) {
            UrlQuery urlQuery = UrlQuery.of(queryString, StandardCharsets.UTF_8);

            urlBuilder.setQuery(urlQuery);
            // Map<CharSequence, CharSequence> queryMap = urlQuery.getQueryMap();
            // Map<String, Object> formMap = new HashMap<>();
            // queryMap.forEach((k, value) -> {
            //     formMap.put((String) k, value);
            // });
            // log.info(JSONUtil.toJsonStr(formMap));
            // httpRequest.form(formMap);
        }

        Method huMethod = Method.valueOf(method.toUpperCase());
        HttpRequest httpRequest = createHttpRequest(huMethod, urlBuilder.build());
        if(contentType != null) {
            httpRequest.contentType(contentType);
        }


        if (StrUtil.isNotBlank(text) && JSONUtil.isJson(text)) {
            log.info("text is json , {}", text);
            httpRequest.body(text, contentType);
        } else if(StrUtil.isNotBlank(text)) {
            log.info("text is not json , {}", text);
            httpRequest.body(text);
        }

        /**
         * 将数据遍历出来
         */
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = request.getHeader(name);
            // log.info("name = {}, value = {}", name, value);
            if ("User-Agent".equalsIgnoreCase(name)
                || "Host".equalsIgnoreCase(name)
                || "X-Forwarded-For".equalsIgnoreCase(name)
                || "X-Real-Ip".equalsIgnoreCase(name)
                || "REMOTE-HOST".equalsIgnoreCase(name)) {
                continue;
            }
            httpRequest.header(name, value, true);
        }

        HttpResponse httpResponse = httpRequest.execute();
        String httpContentType = httpResponse.header("Content-Type");
        String contentEncoding = httpResponse.contentEncoding();
        log.info("httpContentType = {}, status = {}, body = {}", httpContentType, httpResponse.getStatus(), httpResponse.body());
        response.setStatus(httpResponse.getStatus());
        response.setCharacterEncoding(StrUtil.isBlank(contentEncoding) ? "UTF-8" : contentEncoding);
        response.setContentType(StrUtil.isBlank(httpContentType) ? "application/json; charset=UTF-8" : httpContentType);
        httpResponse.writeBody(response.getOutputStream(), true, null);
    }

    /**
     * 创建请求
     * @param huMethod
     * @param requestUrl
     * @return
     */
    private HttpRequest createHttpRequest(Method huMethod, String requestUrl) {
        log.info("huMethod = {}, requestUrl = {}", huMethod, requestUrl);
        HttpRequest httpRequest = HttpUtil.createRequest(huMethod, requestUrl);

        ForwardProperties.ProxyEntry proxy = forwardProperties.getProxy();
        if(proxy != null) {
            httpRequest.setHttpProxy(proxy.getHost(), proxy.getPort());
        }

        return httpRequest;
    }

    /**
     * 获取转发的请求地址
     * @param servletPath
     * @param target
     * @param key
     * @return
     */
    private String getRequestUrl(String servletPath, String target, String key) {
        String requestUrl = null;
        log.info("servletPath = {}, target = {}, key = {}", servletPath, target, key);

        String subPath = StrUtil.subAfter(servletPath, "/" + target + "/" + key + "/", true);
        log.info("subPath = {}", subPath);

        String forwardUrl = ForwardHolder.getForwardUrl(target, key);
        if(StrUtil.isNotBlank(forwardUrl)) {
            boolean isEnd = StrUtil.endWith(forwardUrl, "/");
            if(!isEnd) {
                subPath = "/" + subPath;
            }
            requestUrl = forwardUrl + subPath;
        }

        return requestUrl;
    }


}
